在 ASP.NET 中設定 SameSite Cookies
TLDR
- SameSite 屬性用於限制第三方 Cookie,防禦 CSRF 攻擊。
- SameSite 共有三個值:
None(所有請求發送,需搭配Secure)、Lax(預設值,僅第一方或連結導向發送)、Strict(僅第一方發送)。 - ASP.NET Core 可透過
CookiePolicyOptions進行全域設定,並需處理舊版瀏覽器對None支援度不佳的問題。 - ASP.NET Framework 4.7.2 以上支援
SameSite設定,Session狀態需額外透過<sessionState>設定。 - 瀏覽器實作差異大,建議針對
User-Agent進行相容性檢查。
SameSite Cookies 核心概念
SameSite Cookies 為 IETF 訂立的標準,旨在限制第三方 Cookie 的發送,以防禦跨網站要求偽造 (CSRF) 攻擊。
SameSite 屬性值說明
什麼情況下會遇到這個問題:當需要決定 Cookie 是否應隨跨站請求發送時。
None:Cookie 將在所有情況下的請求發送,現今必須搭配Secure屬性。Lax:現今瀏覽器的預設值,僅在第一方上下文或用戶透過連結 (Link) 到原網站時發送。Strict:Cookie 只會在第一方上下文的請求發送。
Lax 模式下的請求支援度
什麼情況下會遇到這個問題:當應用程式依賴 Cookie 進行登入驗證,且使用者透過外部網站連結進入時。
| 請求方式 | 能否取得 Cookies |
|---|---|
Link (<a>) | O |
| Form Get | O |
| Form Post | X |
| iframe | X |
| AJAX | X |
| Image | X |
WARNING
不論是「Same-Origin Policy」或是「SameSite Cookies」皆高度依賴瀏覽器實作,不同版本間的行為可能存在差異。
在 ASP.NET Core 設定 SameSite Cookies
全域設定與相容性處理
什麼情況下會遇到這個問題:當需要統一管理全站 Cookie 策略,並確保舊版瀏覽器不會因不支援 None 而導致功能異常。
在 Program.cs 中設定 CookiePolicyOptions,並透過 OnAppendCookie 攔截器處理舊版瀏覽器:
csharp
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<CookiePolicyOptions>(options => {
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
options.OnAppendCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
options.OnDeleteCookie = cookieContext =>
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});
void CheckSameSite(HttpContext httpContext, CookieOptions options) {
if (options.SameSite == SameSiteMode.None) {
var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
if (DisallowsSameSiteNone(userAgent)) {
options.SameSite = SameSiteMode.Unspecified;
}
}
}
// ...其他程式碼...
app.UseCookiePolicy(); // 必須放在 UseAuthorization 前面個別 Cookie 設定
什麼情況下會遇到這個問題:當特定 Cookie 需要與全域策略不同的 SameSite 設定時。
csharp
Response.Cookies.Append("name", "value", new CookieOptions() { SameSite = SameSiteMode.Lax });TIP
未設定 SameSiteMode 或指定為 Unspecified 時,瀏覽器將自行決定行為。
在 ASP.NET Framework 設定 SameSite Cookies
設定預設值與 Session
什麼情況下會遇到這個問題:在 Framework 4.7.2 以上環境,需設定全域 Cookie 預設行為。
在 Web.config 中設定:
xml
<configuration>
<system.web>
<!-- 若個別 Cookie 未設定,則以此為準 -->
<httpCookies sameSite="Lax"></httpCookies>
<!-- Session 需額外設定 -->
<sessionState cookieSameSite="Lax"></sessionState>
</system.web>
</configuration>舊瀏覽器相容性處理
什麼情況下會遇到這個問題:在 Framework 環境中,需針對不支援 None 的舊瀏覽器進行動態修正。
在 Global.asax.cs 中攔截回應標頭:
csharp
protected void Application_BeginRequest(object sender, EventArgs e) {
HttpApplication application = sender as HttpApplication;
if (application != null) {
var userAgent = application.Context.Request.UserAgent;
if (DisallowsSameSiteNone(userAgent)) {
HttpContext.Current.Response.AddOnSendingHeaders(context => {
var cookies = context.Response.Cookies;
for (var i = 0; i < cookies.Count; i++) {
var cookie = cookies[i];
if (cookie.SameSite == SameSiteMode.None) {
cookie.SameSite = (SameSiteMode)(-1); // Unspecified
}
}
});
}
}
}WARNING
測試 ASP.NET_SessionId 的 Same-Site 行為時,建議使用無痕模式,以避免受先前瀏覽紀錄影響。
異動歷程
- 2022-10-26 初版文件建立。
